/*******************************************************************************
 * Copyright (c) 2013,  Paul Daniels
 *
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.hupu.jrs.components.jockeyjs

import android.annotation.SuppressLint
import android.os.Handler
import android.util.SparseArray
import android.webkit.WebView
import android.webkit.WebViewClient
import com.hupu.jrs.components.jockeyjs.util.ForwardingWebViewClient
import java.util.*

abstract class JockeyImpl : Jockey {

    private val _listeners = HashMap<String, CompositeJockeyHandler>()
    private val _callbacks = SparseArray<JockeyCallback>()

    private var _onValidateListener: Jockey.OnValidateListener? = null

    private val _handler = Handler()

    private val _client: JockeyWebViewClient

    protected val webViewClient: ForwardingWebViewClient
        get() = this._client

    init {
        _client = JockeyWebViewClient(this)
    }

    override fun send(type: String, toWebView: WebView) {
        send(type, toWebView, null!!)
    }

    override fun send(type: String, toWebView: WebView, withPayload: Any) {
        send(type, toWebView, withPayload, null!!)
    }

    override fun send(type: String, toWebView: WebView, complete: JockeyCallback) {
        send(type, toWebView, null!!, complete)
    }

    override fun on(type: String, vararg handler: JockeyHandler) {

        if (!this.handles(type)) {
            _listeners.put(type, CompositeJockeyHandler())
        }

        _listeners[type]!!.add(*handler)
    }

    override fun off(type: String) {
        _listeners.remove(type)
    }

    override fun handles(eventName: String): Boolean {
        return _listeners.containsKey(eventName)
    }

    protected fun add(messageId: Int, callback: JockeyCallback) {
        _callbacks.put(messageId, callback)
    }

    fun triggerEventFromWebView(webView: WebView, envelope: JockeyWebViewPayload) {
        val messageId = envelope.id
        val type = envelope.type

        if (this.handles(type!!)) {
            val handler = _listeners[type]

            handler!!.perform(envelope.payload!!, object : JockeyHandler.OnCompletedListener {
                override fun onCompleted() {
                    _handler.post({  triggerCallbackOnWebView(webView, messageId)  })
                }
                // This has to be done with a handler because a webview load
                // must be triggered
                // in the UI thread
            })
        }
    }

    fun triggerCallbackForMessage(messageId: Int) {
        try {
            val complete = _callbacks.get(messageId, _DEFAULT)
            complete.call()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        _callbacks.remove(messageId)
    }

    @Throws(HostValidationException::class)
    fun validate(host: String) {
        if (_onValidateListener != null && !_onValidateListener!!.validate(host)) {
            throw HostValidationException()
        }
    }

    override fun setOnValidateListener(listener: Jockey.OnValidateListener) {
        _onValidateListener = listener
    }

    @SuppressLint("SetJavaScriptEnabled")
    override fun configure(webView: WebView) {
        if (webView != null) {
            webView.settings.javaScriptEnabled = true
            webView.webViewClient = this.webViewClient
        }
    }

    override fun setWebViewClient(client: WebViewClient) {
        this._client.setDelegate(client)
    }

    companion object {

        // A default Callback that does nothing.
        protected val _DEFAULT: JockeyCallback = object : JockeyCallback {
            override fun call() {}
        }

        val default: Jockey
            get() = DefaultJockeyImpl()
    }
}
